#include "in.h"

char		__MDB_VERSION_0_0_5_1[] = "0.0.5.1" ;
char		*__MDB_VERSION = __MDB_VERSION_0_0_5_1 ;

/*
__thread char	tls_data_files_path[ PATH_MAX ] = "." ;
*/
__thread int	tls_last_errno = 0 ;

int CreateMemTablesHash( struct MemDatabase *db )
{
	register int			i ;
	register struct hlist_head	*p_hlist_head = NULL ;
	
	db->tables_hash_size = MDB_TABLES_HASH_SIZE ;
	db->tables_hash = (struct hlist_head *)malloc( sizeof(struct hlist_head) * db->tables_hash_size ) ;
	if( db->tables_hash == NULL )
		return MDB_ERROR_ALLOC;
	memset( db->tables_hash , 0x00 , sizeof(struct hlist_head) * db->tables_hash_size );
	
	for( i = 0 , p_hlist_head = db->tables_hash ; i < db->tables_hash_size ; i++ , p_hlist_head++ )
	{
		INIT_HLIST_HEAD( p_hlist_head );
	}
	
	return 0;
}

int DestroyMemTablesHash( struct MemDatabase *db )
{
	register int			i ;
	register struct hlist_head	*p_hlist_head = NULL ;
	struct hlist_node		*p_curr = NULL , *p_next = NULL ;
	struct MemTable			*table = NULL ;
	
	if( db->tables_hash == NULL )
		return 1;
	
	for( i = 0 , p_hlist_head = db->tables_hash ; i < db->tables_hash_size ; i++ , p_hlist_head++ )
	{
		hlist_for_each_safe( p_curr , p_next , p_hlist_head )
		{
			table = container_of(p_curr,struct MemTable,table_hash_node) ;
			TRACE_PRINTF( "MDBDropTableDirectly table[%p][%s]\n" , table , table->table_name );
			MDBDropTableDirectly( db , table );
		}
	}
	
	free( db->tables_hash ); db->tables_hash = NULL ;
	
	return 0;
}

int AddMemTablesHashNodeDirectly( struct MemDatabase *db , struct MemTable *table )
{
	uint32_t			index ;
	struct hlist_head		*p_hlist_head = NULL ;
	register struct MemTable	*p = NULL ;
	
	index = Hash((unsigned char *)(table->table_name),table->table_name_len) % (db->tables_hash_size) ;
	p_hlist_head = db->tables_hash + index ;
	hlist_for_each_entry( p , p_hlist_head , struct MemTable , table_hash_node )
	{
		if( STRCMP( p->table_name , == , table->table_name ) )
			return (tls_last_errno=MDB_ERROR_TABLE_DUPLICATED);
	}
	hlist_add_head( & (table->table_hash_node) , p_hlist_head );
	
	return 0;
}

int RemoveMemTablesHashNode( struct MemDatabase *db , char *table_name )
{
	size_t				table_name_len ;
	uint32_t			index ;
	struct hlist_head		*p_hlist_head = NULL ;
	register struct MemTable	*table = NULL ;
	
	table_name_len = strlen(table_name) ;
	index = Hash((unsigned char *)(table_name),table_name_len) % (db->tables_hash_size) ;
	p_hlist_head = db->tables_hash + index ;
	hlist_for_each_entry( table , p_hlist_head , struct MemTable , table_hash_node )
	{
		if( STRCMP( table->table_name , == , table_name ) )
		{
			RemoveMemTablesHashNodeDirectly( db , table );
			return 0;
		}
	}
	
	return MDB_ERROR_TABLE_NOT_FOUND;
}

int RemoveMemTablesHashNodeDirectly( struct MemDatabase *db , struct MemTable *table )
{
	hlist_del( & (table->table_hash_node) );
	free( table );
	
	return 0;
}

struct MemTable *QueryMemTablesHashNode( struct MemDatabase *db , char *table_name )
{
	size_t				table_name_len ;
	uint32_t			index ;
	struct hlist_head		*p_hlist_head = NULL ;
	register struct MemTable	*table = NULL ;
	
	table_name_len = strlen(table_name) ;
	index = Hash((unsigned char *)(table_name),table_name_len) % (db->tables_hash_size) ;
	p_hlist_head = db->tables_hash + index ;
	hlist_for_each_entry( table , p_hlist_head , struct MemTable , table_hash_node )
	{
		if( table->table_name_len == table_name_len && STRNCMP( table->table_name , == , table_name , table_name_len ) )
			return table;
	}
	
	tls_last_errno = MDB_ERROR_TABLE_NOT_FOUND ;
	return NULL;
}

/*
void MDBSetDataFilesPath( char *path )
{
	memset( tls_data_files_path , 0x00 , sizeof(tls_data_files_path) );
	strncpy( tls_data_files_path , path , sizeof(tls_data_files_path)-1 );
	
	return;
}
*/

struct MemDatabase *MDBCreateDatabase( char *db_name )
{
	struct MemDatabase	*db = NULL ;
	
	int			nret = 0 ;
	
	db = (struct MemDatabase *)malloc( sizeof(struct MemDatabase) ) ;
	if( db == NULL )
	{
		tls_last_errno = MDB_ERROR_ALLOC ;
		return NULL;
	}
	memset( db , 0x00 , sizeof(struct MemDatabase) ) ;
	
	db->db_name_len = strlen(db_name) ;
	if( db->db_name_len >= MDB_DATABASE_NAME_MAX_LENGTH )
	{
		tls_last_errno = MDB_ERROR_DATABASE_NAME_TOO_LONG ;
		return NULL;
	}
	strcpy( db->db_name , db_name );
	
	nret = CreateMemTablesHash( db ) ;
	if( nret < 0 )
	{
		MDBDropDatabase( db );
		return NULL;
	}
	
	db->max_txn_no = 0 ;
	
#if 0
	INIT_LIST_HEAD( & (db->txn_datapage_list) );
	db->txn_datapage_count = 0 ;
#endif
	
	db->is_in_txn = 0 ;
	db->txn.txn_no = 0 ;
	INIT_LIST_HEAD( & (db->txn.undo_list) );
	db->txn.executed_undo = NULL ;
	
	INIT_LIST_HEAD( & (db->undo_datapage_list) );
	db->undo_datapage_count = 0 ;
	
	return db;
}

int MDBDropDatabase( struct MemDatabase *db )
{
	DestroyMemTablesHash( db );
	
	TRACE_PRINTF( "FreeDataPageDirectly db[%p][%s] undo_datapage_list\n" , db , (char*)db );
	FreeDataPageDirectly( & (db->undo_datapage_list) );
	
	free( db );
	
	return 0;
}

int MDBGetLastError()
{
	return tls_last_errno;
}

